package com.zd.service.impl;

import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import com.zd.dao.SeckillDao;
import com.zd.dao.SuccessKillDao;
import com.zd.dto.Exposer;
import com.zd.dto.SeckillExecution;
import com.zd.entity.Seckill;
import com.zd.entity.SuccessKilled;
import com.zd.enums.SeckillStateEnum;
import com.zd.exception.RepeatKillException;
import com.zd.exception.SeckillCloseExecption;
import com.zd.exception.SeckillExecption;
import com.zd.service.SeckillService;
@Service("seckillService")
public class SeckillServiceImpl implements SeckillService{
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	//md5盐字符串，用于混淆md5
	private final String slat = "sdfdf23rtfdsd";
	@Autowired
	private SeckillDao seckillDao;
	@Autowired
	private SuccessKillDao successKillDao;
	
	@Override
	public List<Seckill> getSeckillList() {
		// TODO Auto-generated method stub
		
		return seckillDao.queryAll(0, 100);
	}

	@Override
	public Seckill getById(long seckillId) {
		// TODO Auto-generated method stub
		return seckillDao.queryById(seckillId);
	}

	@Override
	public Exposer exportSeckillUrl(long seckillId) {
		// TODO Auto-generated method stub
		Seckill seckill = seckillDao.queryById(seckillId);
		if(seckill == null){
			return new Exposer(false, seckillId);
		};
		Date startTime = seckill.getStartTime();
		Date endTime = seckill.getEndTime();
		Date nowTime = new Date();
		
		if(nowTime.getTime() < startTime.getTime() || nowTime.getTime() > endTime.getTime()){
			return new Exposer(false,seckillId,nowTime.getTime(),startTime.getTime(),endTime.getTime());
		}
		
		String md5 = getMD5(seckillId);
		return new Exposer(true, seckillId, md5);
		
	}
	@Override
	@Transactional
	/**
	 * 使用注解事务方法的优点：
	 * 1.开发团队达到一致的约定，明确标注事务的编程风格
	 * 2.保证事务方法执行时间尽可能的短，减少网络操作
	 * 3.不是所有的方法都需要事务
	 */
	public SeckillExecution executeSeckill(long seckillId, long userPhone,
			String md5) throws SeckillExecption, RepeatKillException,
			SeckillCloseExecption {
		// TODO Auto-generated method stub
		try {
			if(md5 == null || !md5.equals(getMD5(seckillId))){
				throw new SeckillExecption("seckill data rewrite");
			}
			
			Date nowTime = new Date();
			//减库存
			int updateCount = seckillDao.reduceNumber(seckillId, nowTime);
			if(updateCount <= 0){
				throw new SeckillCloseExecption("seckill is closed");
			}else{
				//记录购买行为
				int insertNumber = successKillDao.insertSuccessKilled(seckillId, userPhone);
				if(insertNumber <= 0){
					throw new RepeatKillException("reckill repeated");
				}else{
					SuccessKilled successKilled = successKillDao.queryByIdWithSeckill(seckillId, userPhone);
					return new SeckillExecution(seckillId,SeckillStateEnum.SUCCESS,successKilled);
				}
			}
		}catch(SeckillCloseExecption e1){
			throw e1;
		}catch(RepeatKillException e2){
			throw e2;
		}
		catch (Exception e) {
			// TODO: handle exception
			logger.error(e.getMessage(),e);
			throw new SeckillExecption("seckill inner error"+e.getMessage());
		}
		
		
	}
	
	private String getMD5(long seckillId){
		String base = seckillId +"/"+slat;
		String md5 = DigestUtils.md5DigestAsHex(base.getBytes());
		return md5;
	}

}
